package com.zmq.controller;

import com.zmq.bean.UserBean;
import com.zmq.service.login.ILoginService;
import com.zmq.utils.AESUtil;
import com.zmq.utils.RandomValidateCodeUtil;
import com.zmq.utils.Tools;
import com.zmq.utils.redis.IRedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
public class LoginController {

    @Autowired
    private ILoginService loginService;

    @Autowired
    private IRedisService redisService;

    private final static Logger logger = LoggerFactory.getLogger(LoginController.class);

    /**
     * 规定登录错误多少次后锁定该账号。
     */
    private int lockNum = 5;

    @RequestMapping("login")
    @ResponseBody
    public Map login(UserBean userBean, String imgCode, HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        Map map = new HashMap();
        //请求体，账号，密码不能为空
        if (userBean == null) {
            map.put("code", false);
            map.put("msg", "空的？怎么可能登录成功呢？");
            return map;
        }
        if (StringUtils.isEmpty(userBean.getUsername())) {
            map.put("code", false);
            map.put("msg", "账号不能为空！");
            return map;
        }
        if (StringUtils.isEmpty(userBean.getPassword())) {
            map.put("code", false);
            map.put("msg", "密码不能为空！");
            return map;
        }
        //验证码不能为空
        if (StringUtils.isEmpty(imgCode)) {
            map.put("code", false);
            map.put("msg", "验证码不能为空！");
            return map;
        }
        //判断验证码是否正确
        boolean imageCode = checkVerify(imgCode, session);
        //TODO 验证码未验证
        if (!true) {
            map.put("code", false);
            map.put("msg", "验证码错误！");
            return map;
        }

        //根据用户名查找用户
        UserBean user = loginService.getUserByUsername(userBean.getUsername());
        //判断是否查找到账号
        if (user == null) {
            map.put("code", false);
            map.put("msg", "账号不存在！");
            return map;
        }
        if (user.getStatus() == 1) {
            map.put("code", false);
            map.put("msg", "账号被锁定，请明天再试！");
            map.put("icon", "4");
            return map;
        }
        if (user.getStatus() == 2) {
            map.put("code", false);
            map.put("msg", "账号被锁定，请联系管理员！");
            map.put("icon", "4");
            return map;
        }
        //获取登陆错误次数
        Integer errorCount = user.getLoginErrorCount();
        //上次登陆时间
        Date lastLoginTime = user.getLastLoginTime();
        //判断登陆错误次数
        if (errorCount >= lockNum) {
            user.setLoginErrorCount(0);
            user.setStatus(1);
            loginService.updateUser(user);
            map.put("code", false);
            map.put("msg", "账号被锁定，请明天再试！");
            map.put("icon", "4");
            return map;
        }
        //System.out.println(userBean.getPassword() + "-----" + Md5Util.getMD5(userBean.getPassword()));
        //验证密码
        if (!userBean.getPassword().equals(user.getPassword())) {
            //密码错误时修改登陆错误时间，次数
            user.setLoginErrorTime(new Date());
            user.setLoginErrorCount(user.getLoginErrorCount() + 1);
            loginService.updateUser(user);
            if (user.getLoginErrorCount() == lockNum - 1) {
                map.put("code", false);
                map.put("msg", "登陆次数已达到" + (lockNum - 1) + "次，还剩最后一次！");
                return map;
            }
            map.put("code", false);
            map.put("msg", "密码错误！");
            return map;
        }


        //登陆成功后
        request.getSession().setAttribute("user_session", user);
        //将session保存到redis,返回一个用户的ticket
        String ticket = saveSessionToRedis(user, user.getPassword());

        //将sessionID放到cookie返回给浏览器存储
        Cookie cookie = new Cookie("COOKIE_SESSION", ticket);
        //设置路径
        cookie.setPath(request.getContextPath() + "/");
        //设置cookie过期时间
        cookie.setMaxAge(30 * 60);
        //返回cookie
        response.addCookie(cookie);

        //更新登陆成功次数,清空错误次数,修改登陆成功时间
        user.setLoginCount(user.getLoginCount() + 1);
        user.setLoginErrorCount(0);
        user.setLastLoginTime(new Date());
        //设置登录成功者的IP
        user.setRegisterIp(Tools.getIPAddress(request));
        loginService.updateUser(user);

        map.put("code", true);
        map.put("msg", "登录成功！今天已登录" + user.getLoginCount() + "次！");
        //map.put("msg", "登录成功！");
        return map;
    }

    /**
     * 保存session到redis
     *
     * @param user
     * @param password
     * @return
     */
    private String saveSessionToRedis(UserBean user, String password) {
        //最难得也是最需要注意的是key的生成
        //首先将用户的唯一标示进行加密(登录名和密码)加密算法是AES
        String sessionID = AESUtil.parseByte2HexStr(AESUtil.encrypt(user.getUsername(), password));
        //生成一个登录唯一判断的key,
        String unique_ticket = "USER_LOGIN_" + sessionID;
        //才是用于session存储的key
        String ticket = "USER_LOGIN_" + sessionID + System.currentTimeMillis();
        //判断该用户是否登录过，如果登录过就将原来的session给删除
        if (redisService.hasKey(unique_ticket)) {
            redisService.del(String.valueOf(redisService.get(unique_ticket)));
        }
        //加入数据到redis
        redisService.set(unique_ticket, ticket);
        redisService.set(ticket, user);
        //设置session的失效时间
        redisService.setExpire(ticket, 30 * 60L, TimeUnit.SECONDS);
        return ticket;
    }

    /**
     * 退出登陆
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("logout")
    public String logout(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String sessionID = "";
        //获取cookie
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            response.sendRedirect("/toLogin");
            return "login";
        }
        //从Cookies中获取自己想要的cookie
        for (Cookie cookie : cookies) {
            if ("COOKIE_SESSION".equals(cookie.getName())) {
                sessionID = cookie.getValue().toString();
            }
        }
        //cookie不能是空
        if ("".equals(sessionID)) {
            response.sendRedirect("/toLogin");
            return "login";
        }
        //删除带时间戳的redisKey
        redisService.del(sessionID);

        return "index";
    }


    /**
     * 生成验证码
     */
    @RequestMapping(value = "/getVerify")
    public void getVerify(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
            response.setHeader("Pragma", "No-cache");//设置响应头信息，告诉浏览器不要缓存此内容
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expire", 0);
            RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
            randomValidateCode.getRandcode(request, response);//输出验证码图片方法
        } catch (Exception e) {
            logger.error("获取验证码失败>>>>   ", e);
        }
    }

    /**
     * 校验验证码
     */
    @RequestMapping(value = "/checkVerify", method = RequestMethod.POST, headers = "Accept=application/json")
    @ResponseBody
    public boolean checkVerify(@RequestParam String verifyInput, HttpSession session) {
        try {
            //从session中获取随机数
            String inputStr = verifyInput.toLowerCase();
            String random = (String) session.getAttribute("RANDOMVALIDATECODEKEY");
            if (random == null) {
                return false;
            }
            if (random.toLowerCase().equals(inputStr)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.error("验证码校验失败", e);
            return false;
        }
    }
}
